/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package fr.ove.openmath.mathematica;

/**
 *
 * @author Mr.Sam
 */
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.awt.*;
import java.util.*;
import java.beans.PropertyVetoException;

/**
* An extension of a JDesktopPane which handles the position of the new inner frames
* created, names them automatically, etc.
*
* 
*/
public class Desktop extends JDesktopPane {
    /**
    * The total number of inner frames opened.
    */
    private int nbUntitled = 0;
    
    /**
    * The next position of the next inner frame opened.
    */
    private Point framePosition = new Point(0,0);
    
    /**
    * The list of inner frames currently opened.
    */
    private Hashtable listOpened = new Hashtable();
    
    /**
    * Keeps the right order of inner frames opened
    */
    private Vector orderOpened = new Vector();
    
    /**
    * The list of content pane of the palette we want to have in the desktop.
    */
    private Hashtable palettesContentPanes;
        
    /**
    * Indicates if the new inner frame created is opened with its maximal size.<BR>
    * The default is not.
    */
    private boolean maximize = false;
    
    /**
    * The Constructor.
    */
    public Desktop() {
        setOpaque(false);
    }
    
    /**
    * Adds a new inner frame with the specified content pane.
    * @param contentPane the specified content pane.
    * @return the inner frame added.
    */
    public JInternalFrame addNewInternalFrame(Container contentPane) {
        JInternalFrame jif = createJInternalFrame(contentPane);
        listOpened.put(jif.getTitle(), jif);
        orderOpened.addElement(jif);
        setLayer(jif, JLayeredPane.DEFAULT_LAYER.intValue());
        add(jif);
        try { 
            Dimension size = jif.getContentPane().getPreferredSize();
            jif.setBounds(framePosition.x, framePosition.y, size.width, size.height);
            computeNextFramePosition();
            
            if (maximize)
                jif.setMaximum(true);
            
            jif.setSelected(true);
            jif.setVisible(true);
            
        } catch (PropertyVetoException pve) {
            pve.printStackTrace();
        }
        
        return jif;
    }
    
    /**
    * Add a new inner frame into the desktop that serves as a palette. It remains above
    * the other "normal" inner frames which are in the desktop.
    * @param contentPane the content of the inner frame.
    *
    public void addNewPalette(Container contentPane) {
        JInternalFrame jif = new MyJInternalFrame("Palette Editor", this);
        jif.setResizable(false);
        jif.setClosable(true);
        jif.setIconifiable(true);
        jif.setMaximizable(false);
        jif.setContentPane(contentPane);
        setLayer(jif, JLayeredPane.PALETTE_LAYER.intValue());
        try { 
            jif.pack();
            jif.setSelected(true);
            jif.setVisible(true);
            
        } catch (PropertyVetoException pve) {
            pve.printStackTrace();
        }
        
        add(jif);
    }*/
    
    /**
    * Adds a new palette to the desktop.
    * @param paletteIdentifier the palette identfier.
    * @param contentPan the palette (i.e. the content pane for the inner frame opened in the desktop)
    */
    public void addNewPaletteContentPane(String paletteIdentifier, Container contentPane) {
        if (palettesContentPanes == null)
            palettesContentPanes = new Hashtable();
            
        palettesContentPanes.put(paletteIdentifier, contentPane);
    }
    
    /**
    * Shows the palette with the specified name identfier.
    * @param identfier the palette identifier.
    */
    public void showPalette(String paletteIdentifier) {
        Container contentPane = (Container) palettesContentPanes.get(paletteIdentifier);
        if (contentPane != null) {
            // cheks if it is alreday showed.
            JInternalFrame[] allJifs = getAllFramesInLayer(JLayeredPane.PALETTE_LAYER.intValue());
            JInternalFrame jif = null;
            for (int i = 0; i < allJifs.length; i++) {
                if (allJifs[i].getTitle().equals(paletteIdentifier))
                    return;
            }
            
            
            jif = new MyJInternalFrame(paletteIdentifier, this);
            jif.setResizable(false);
            jif.setClosable(true);
            jif.setIconifiable(true);
            jif.setMaximizable(false);
            jif.setContentPane(contentPane);
            setLayer(jif, JLayeredPane.PALETTE_LAYER.intValue());
            try { 
                jif.pack();
                jif.setSelected(true);
                jif.setVisible(true);
                
            } catch (PropertyVetoException pve) {
                pve.printStackTrace();
            }
            
            add(jif);
        }
    }
    
    /**
    * Removes (and close) the specified inner frame from the desktop.
    * @param jif the inner frame to remove.
    */
    public JInternalFrame removeInternalFrame(JInternalFrame jif) {
        if (listOpened.contains(jif)) {
            String key;
            JInternalFrame value;
            for (Enumeration e = listOpened.keys(); e.hasMoreElements(); ) {
                key = (String) e.nextElement();
                value = (JInternalFrame) listOpened.get(key);
                if (value == jif) {
                    listOpened.remove(key);
                    orderOpened.removeElement(jif);
                    return value;
                }
            }
        }
        return null;
    }
    
    /**
    * Removes (and close) the inner frame with the specified name from the desktop.
    * @param name the name of the inner frame to remove.
    */
    public JInternalFrame removeInternalFrame(String name) {
        JInternalFrame jif = null;
        for (Enumeration e = orderOpened.elements(); e.hasMoreElements(); ) {
            jif = (JInternalFrame) e.nextElement();
            if (name.equals(jif.getTitle())) {
                orderOpened.removeElement(jif);
                listOpened.remove(name);
                break;
            }
        }
        return jif;
    }
    
    /**
    * Gets the inner frame with specified name.
    * @param name the name of the inner frame.
    * @return the inner frame with the corresponding name. 
    * <CODE>null</CODE> otherwise.
    */
    public JInternalFrame getInternalFrame(String name) {
        return (JInternalFrame) listOpened.get(name);
    }
    
    /**
    * Gets the active inner frame in the desktop.
    * @return the active inner frame if any. 
    * <CODE>null</CODE> otherwise.
    */
    public JInternalFrame getActiveInternalFrame() {
        return getActiveInternalFrameFrom(JLayeredPane.DEFAULT_LAYER.intValue());
    }
    
    /**
    * Gets the active palette in the desktop.
    * @return the active inner frame if any. <CODE>null</CODE> otherwise.
    */
    public JInternalFrame getActivePalette() {
        return getActiveInternalFrameFrom(JLayeredPane.PALETTE_LAYER.intValue());
    }
    
    /**
    * Gets the active inner frame in the desktop in the specified layer.
    * @param layer the layer indentifier.
    * @return the active inner frame if any. <CODE>null</CODE> otherwise.
    */
    private JInternalFrame getActiveInternalFrameFrom(int layer) {
        JInternalFrame[] allJifs = getAllFramesInLayer(layer);
        JInternalFrame jif = null;
        
        for (int i = 0; i < allJifs.length; i++) {
            jif = allJifs[i];
            if (jif.isSelected())
                break;
        }
        
        return jif;
    }
    
    /**
    * Selects the inner frame with the specified name
    * @param name the specified name.
    */
    public void setSelected(String name) {
        JInternalFrame jif = (JInternalFrame) listOpened.get(name);
        if (jif != null) {
            try { 
                jif.setSelected(true);
            } catch (PropertyVetoException pve) {
                pve.printStackTrace();
            }
        }
    }
    
    /**
    * Renames the inner frame.
    * @param currentName the current name of the inner frame.
    * @param newName the new name of the inner frame.
    */
    public void rename(String currentName, String newName) throws Exception {
        JInternalFrame jif = (JInternalFrame) listOpened.remove(currentName);
        if (jif != null) {
            if (listOpened.containsKey(newName))
                throw new Exception("There already exists an inner frame with the name : " + newName);
             else {
                listOpened.put(newName, jif);
                jif.setTitle(newName);
             }
        }
        else
            throw new Exception("There is no inner frame with the name : " + currentName);
        
    }
    
    /**
    * Creates a new inner frame with the specified content pane.
    * @param contentPane the specified content pane.
    * @return the inner frame added.
    */
    private JInternalFrame createJInternalFrame(Container contentPane) {
        JInternalFrame jif = new MyJInternalFrame("Untitled-" + ++nbUntitled, this);
        jif.setResizable(true);
        jif.setClosable(true);
        jif.setIconifiable(true);
        jif.setMaximizable(true);
        jif.setContentPane(contentPane);
        return jif;
    }
    
    /**
    * Compute the postion of the next inner frame created.
    */
    private void computeNextFramePosition() {
        Dimension size = getSize();
        framePosition.x = (framePosition.x > size.width/2) ? 0 : framePosition.x + 25;
        framePosition.y = (framePosition.y > size.height/2) ? 0 : framePosition.y + 30;        
    }
    
    /**
    * Sets all the inner frames to their maximum size.
    */
    public void setAllMaximum() {
        String key;
        JInternalFrame value;
        for (Enumeration e = listOpened.keys(); e.hasMoreElements(); ) {
            key = (String) e.nextElement();
            value = (JInternalFrame) listOpened.get(key);
            try {
                value.setMaximum(maximize);
            } catch (PropertyVetoException pve) {
                pve.printStackTrace();
            }
        }
        
    }
    
    /**
    *
    */
    public void setMaximize(boolean maximize) {
        this.maximize = maximize;
    }
    
    /**
    * Cascades the frame in the desktop.
    */
    public void cascade() {
        framePosition.x = 0;
        framePosition.y = 0;
        JInternalFrame jif;
        for (Enumeration e = orderOpened.elements(); e.hasMoreElements(); ) {
            jif = (JInternalFrame) e.nextElement();
            jif.setLocation(framePosition.x, framePosition.y);
            setSelected(jif.getTitle());
            computeNextFramePosition();
        }
    }
    
    /**
    * Closes all the frames in the desktop.
    */
    public void closeAll() {
        JInternalFrame[] allJifs = getAllFramesInLayer(JLayeredPane.DEFAULT_LAYER.intValue());
        for (int i = 0; i < allJifs.length; i++) {
            try {
                allJifs[i].setClosed(true);
            }
            catch (PropertyVetoException pve) {
            }
        }
        framePosition.x = 0;
        framePosition.y = 0;        
    }
        
}
